In [1]:
Copied!
import pathpyG as pp
import torch
from pathpyG.nn.dbgnn import DBGNN
from torch_geometric.transforms import RandomNodeSplit
import torch_geometric
from sklearn.manifold import TSNE
import numpy as np
import matplotlib.pyplot as plt
import scipy as sp
pp.config['torch']['device'] = 'cpu'
device = pp.config['torch']['device']
import pathpyG as pp
import torch
from pathpyG.nn.dbgnn import DBGNN
from torch_geometric.transforms import RandomNodeSplit
import torch_geometric
from sklearn.manifold import TSNE
import numpy as np
import matplotlib.pyplot as plt
import scipy as sp
pp.config['torch']['device'] = 'cpu'
device = pp.config['torch']['device']
Load the synthetic dataset¶
In [63]:
Copied!
# Read temporal network
t = pp.TemporalGraph.from_csv('../data/temporal_clusters.tedges')
# Read temporal network
t = pp.TemporalGraph.from_csv('../data/temporal_clusters.tedges')
In [3]:
Copied!
node_colors = ['green']*10+['red']*10+['blue']*10
node_colors = ['green']*10+['red']*10+['blue']*10
In [4]:
Copied!
style = {}
style['node_color'] = node_colors
style = {}
style['node_color'] = node_colors
In [5]:
Copied!
pp.plot(t, **style);
pp.plot(t, **style);
In [6]:
Copied!
# read the paths
paths_original = pp.PathData.from_csv('../data/temporal_clusters.ngram')
print(paths_original)
print(paths_original.num_nodes)
# read the paths
paths_original = pp.PathData.from_csv('../data/temporal_clusters.ngram')
print(paths_original)
print(paths_original.num_nodes)
PathData with 7460 walks and 0 dags and total weight 29042 30
In [7]:
Copied!
#caluclate paths
dag = pp.algorithms.temporal_graph_to_event_dag(t, delta=1)
print(dag)
#caluclate paths
dag = pp.algorithms.temporal_graph_to_event_dag(t, delta=1)
print(dag)
Graph with 89032 nodes and 60000 edges Node attributes node_name <class 'list'> node_id <class 'list'> node_idx <class 'list'> Edge attributes edge_ts <class 'torch.Tensor'> -> torch.Size([60000]) Graph attributes num_nodes <class 'int'>
In [8]:
Copied!
paths = pp.PathData.from_temporal_dag(dag)
paths.node_id = t.data.node_id
print(paths)
paths = pp.PathData.from_temporal_dag(dag)
paths.node_id = t.data.node_id
print(paths)
PathData with 29032 walks and 0 dags and total weight 29032
In [9]:
Copied!
print(len(set([tuple(pp.PathData.walk_to_node_seq(v).tolist()) for v in paths.paths.values()])))
print(len(set([tuple(pp.PathData.walk_to_node_seq(v).tolist()) for v in paths.paths.values()])))
7078
In [10]:
Copied!
# Create the graph corresponding to paths
g = pp.HigherOrderGraph(paths, order=1)
# Plotting the time-aggregated network (first-order graph)
pp.plot(g);
# Create the graph corresponding to paths
g = pp.HigherOrderGraph(paths, order=1)
# Plotting the time-aggregated network (first-order graph)
pp.plot(g);
In [65]:
Copied!
# Create the second-order graph corresponding to paths
g2 = pp.HigherOrderGraph(paths, order=2, node_id=t.data.node_id)
# Plotting the second-order graph
pp.plot(g2);
# Create the second-order graph corresponding to paths
g2 = pp.HigherOrderGraph(paths, order=2, node_id=t.data.node_id)
# Plotting the second-order graph
pp.plot(g2);
In [12]:
Copied!
t_shuffled = pp.TemporalGraph.from_csv('../data/temporal_clusters.tedges')
t_shuffled.data['t'] = t.data['t'][torch.randperm(len(t_shuffled.data['t']))]
t_shuffled = pp.TemporalGraph.from_csv('../data/temporal_clusters.tedges')
t_shuffled.data['t'] = t.data['t'][torch.randperm(len(t_shuffled.data['t']))]
In [13]:
Copied!
t.data.t
t.data.t
Out[13]:
tensor([ 0, 1, 2, ..., 59997, 59998, 59999])
In [14]:
Copied!
t_shuffled.data.t
t_shuffled.data.t
Out[14]:
tensor([21541, 5967, 30001, ..., 8319, 17186, 28812])
In [15]:
Copied!
#caluclate paths
dag_shuffled = pp.algorithms.temporal_graph_to_event_dag(t_shuffled, delta=1)
print(dag_shuffled)
#caluclate paths
dag_shuffled = pp.algorithms.temporal_graph_to_event_dag(t_shuffled, delta=1)
print(dag_shuffled)
Graph with 118015 nodes and 60000 edges Node attributes node_name <class 'list'> node_id <class 'list'> node_idx <class 'list'> Edge attributes edge_ts <class 'torch.Tensor'> -> torch.Size([60000]) Graph attributes num_nodes <class 'int'>
In [16]:
Copied!
paths_shuffled = pp.PathData.from_temporal_dag(dag_shuffled)
print(paths_shuffled)
print(paths_shuffled.num_nodes)
paths_shuffled = pp.PathData.from_temporal_dag(dag_shuffled)
print(paths_shuffled)
print(paths_shuffled.num_nodes)
PathData with 58015 walks and 0 dags and total weight 58015 30
In [66]:
Copied!
# Create the second-order graph corresponding to paths
g2_shuffled = pp.HigherOrderGraph(paths_shuffled, order=2, node_id=t_shuffled.data.node_id)
print(g2_shuffled)
# Plotting the second-order graph
pp.plot(g2_shuffled);
# Create the second-order graph corresponding to paths
g2_shuffled = pp.HigherOrderGraph(paths_shuffled, order=2, node_id=t_shuffled.data.node_id)
print(g2_shuffled)
# Plotting the second-order graph
pp.plot(g2_shuffled);
HigherOrderGraph (k=2) with 863 nodes and 1886 edges Total edge weight = 1985.0 Edge attributes edge_weight <class 'torch.Tensor'> -> torch.Size([1886]) Graph attributes num_nodes <class 'int'> node_id <class 'list'>
Spectral clustering with second-order graph Laplacian¶
In [55]:
Copied!
#g2.to_undirected()
L = g2.get_laplacian(normalization='rw', edge_attr='edge_weight')
#g2_shuffled.to_undirected()
L_shuffled= g2_shuffled.get_laplacian(normalization='rw',edge_attr='edge_weight')
#g2.to_undirected()
L = g2.get_laplacian(normalization='rw', edge_attr='edge_weight')
#g2_shuffled.to_undirected()
L_shuffled= g2_shuffled.get_laplacian(normalization='rw',edge_attr='edge_weight')
In [56]:
Copied!
w,v = sp.linalg.eig(L.todense(),left= False, right = True)
w_shuffled, v_shuffled = sp.linalg.eig(L_shuffled.todense())
w,v = sp.linalg.eig(L.todense(),left= False, right = True)
w_shuffled, v_shuffled = sp.linalg.eig(L_shuffled.todense())
In [57]:
Copied!
fiedler = v[:,np.argsort(w)[1]]
fiedler_shuffled = v_shuffled[:,np.argsort(w_shuffled)[1]]
fiedler = v[:,np.argsort(w)[1]]
fiedler_shuffled = v_shuffled[:,np.argsort(w_shuffled)[1]]
In [84]:
Copied!
c=[]
a=[]
for v in g2.nodes:
if int(v[0])<10 and int(v[1])<10:
c.append('green')
a.append(1)
elif int(v[0])<20 and int(v[0])>= 10 and int(v[1])<20 and int(v[1])>=10:
c.append('red')
a.append(1)
elif int(v[0])<30 and int(v[0])>= 20 and int(v[1])<30 and int(v[1])>=20:
c.append('blue')
a.append(1)
else:
c.append('black')
a.append(0.1)
c=[]
a=[]
for v in g2.nodes:
if int(v[0])<10 and int(v[1])<10:
c.append('green')
a.append(1)
elif int(v[0])<20 and int(v[0])>= 10 and int(v[1])<20 and int(v[1])>=10:
c.append('red')
a.append(1)
elif int(v[0])<30 and int(v[0])>= 20 and int(v[1])<30 and int(v[1])>=20:
c.append('blue')
a.append(1)
else:
c.append('black')
a.append(0.1)
In [88]:
Copied!
c_shuffled=[]
a_shuffled=[]
for v in g2_shuffled.nodes:
if int(v[0])<10 and int(v[1])<10:
c_shuffled.append('green')
a_shuffled.append(1)
elif int(v[0])<20 and int(v[0])>= 10 and int(v[1])<20 and int(v[1])>=10:
c_shuffled.append('red')
a_shuffled.append(1)
elif int(v[0])<30 and int(v[0])>= 20 and int(v[1])<30 and int(v[1])>=20:
c_shuffled.append('blue')
a_shuffled.append(1)
else:
c_shuffled.append('black')
a_shuffled.append(0.1)
c_shuffled=[]
a_shuffled=[]
for v in g2_shuffled.nodes:
if int(v[0])<10 and int(v[1])<10:
c_shuffled.append('green')
a_shuffled.append(1)
elif int(v[0])<20 and int(v[0])>= 10 and int(v[1])<20 and int(v[1])>=10:
c_shuffled.append('red')
a_shuffled.append(1)
elif int(v[0])<30 and int(v[0])>= 20 and int(v[1])<30 and int(v[1])>=20:
c_shuffled.append('blue')
a_shuffled.append(1)
else:
c_shuffled.append('black')
a_shuffled.append(0.1)
In [83]:
Copied!
plt.ylim(-.2, .25)
plt.scatter(range(g2.data.num_nodes), np.real(fiedler),c=c, alpha=a )
plt.ylim(-.2, .25)
plt.scatter(range(g2.data.num_nodes), np.real(fiedler),c=c, alpha=a )
Out[83]:
<matplotlib.collections.PathCollection at 0x2c1211090>
In [87]:
Copied!
plt.ylim(-.1, .1)
plt.scatter(range(g2_shuffled.data.num_nodes), fiedler_shuffled, c=c_shuffled, alpha=a_shuffled)
plt.ylim(-.1, .1)
plt.scatter(range(g2_shuffled.data.num_nodes), fiedler_shuffled, c=c_shuffled, alpha=a_shuffled)
/Users/franziskaheeg/miniconda3/envs/pathpy3.10/lib/python3.10/site-packages/matplotlib/cbook.py:1699: ComplexWarning: Casting complex values to real discards the imaginary part return math.isfinite(val) /Users/franziskaheeg/miniconda3/envs/pathpy3.10/lib/python3.10/site-packages/matplotlib/collections.py:194: ComplexWarning: Casting complex values to real discards the imaginary part offsets = np.asanyarray(offsets, float)
Out[87]:
<matplotlib.collections.PathCollection at 0x2c121b1f0>
Prepare the data¶
In [23]:
Copied!
# Define edge indices for first and second-order graphs
edge_index_g1 = g.data.edge_index
edge_index_g2 = g2.data.edge_index
# Define edge indices for first and second-order graphs
edge_index_g1 = g.data.edge_index
edge_index_g2 = g2.data.edge_index
In [24]:
Copied!
# Define edge weights
edge_weights = g.data['edge_weight']
edge_weights_higher_order = g2.data['edge_weight']
# Define edge weights
edge_weights = g.data['edge_weight']
edge_weights_higher_order = g2.data['edge_weight']
In [25]:
Copied!
# Define bipartite mapping
import torch
def generate_bipatite_edge_index(mapping = 'last'):
if mapping == 'last':
bipartide_edge_index = torch.tensor([list(g2.node_index_to_id.keys()),
[i[1] for i in g2.node_index_to_id.values()]])
elif mapping == 'first':
bipartide_edge_index = torch.tensor([list(g2.node_index_to_id.keys()),
[i[0] for i in g2.node_index_to_id.values()]])
else:
bipartide_edge_index = torch.tensor([list(g2.node_index_to_id.keys()) + list(g2.node_index_to_id.keys()),
[i[0] for i in g2.node_index_to_id.values()] + [i[1] for i in g2.node_index_to_id.values()]])
return bipartide_edge_index
# Original DBGNN implementation mapping = 'last'
bipatite_edge_index = generate_bipatite_edge_index(mapping='last')
# Define bipartite mapping
import torch
def generate_bipatite_edge_index(mapping = 'last'):
if mapping == 'last':
bipartide_edge_index = torch.tensor([list(g2.node_index_to_id.keys()),
[i[1] for i in g2.node_index_to_id.values()]])
elif mapping == 'first':
bipartide_edge_index = torch.tensor([list(g2.node_index_to_id.keys()),
[i[0] for i in g2.node_index_to_id.values()]])
else:
bipartide_edge_index = torch.tensor([list(g2.node_index_to_id.keys()) + list(g2.node_index_to_id.keys()),
[i[0] for i in g2.node_index_to_id.values()] + [i[1] for i in g2.node_index_to_id.values()]])
return bipartide_edge_index
# Original DBGNN implementation mapping = 'last'
bipatite_edge_index = generate_bipatite_edge_index(mapping='last')
In [26]:
Copied!
# Define the PyG data object
from torch_geometric.data import Data
num_nodes = max(max(g.data['edge_index'][0]), max(g.data['edge_index'][1])).item() + 1 # since indexing starts from 0
num_ho_nodes = max(max(g2.data['edge_index'][0]), max(g2.data['edge_index'][1])).item() + 1 # since indexing starts from 0
data = Data(
num_nodes = num_nodes,
num_ho_nodes = num_ho_nodes,
x = torch.eye(num_nodes, num_nodes),
x_h = torch.eye(num_ho_nodes, num_ho_nodes),
edge_index = edge_index_g1,
edge_index_higher_order = edge_index_g2,
edge_weights = edge_weights.float(),
edge_weights_higher_order = edge_weights_higher_order.float(),
bipartite_edge_index = bipatite_edge_index,
y = torch.tensor([ int(i) // 10 for i in paths.node_id])
)
# Define the PyG data object
from torch_geometric.data import Data
num_nodes = max(max(g.data['edge_index'][0]), max(g.data['edge_index'][1])).item() + 1 # since indexing starts from 0
num_ho_nodes = max(max(g2.data['edge_index'][0]), max(g2.data['edge_index'][1])).item() + 1 # since indexing starts from 0
data = Data(
num_nodes = num_nodes,
num_ho_nodes = num_ho_nodes,
x = torch.eye(num_nodes, num_nodes),
x_h = torch.eye(num_ho_nodes, num_ho_nodes),
edge_index = edge_index_g1,
edge_index_higher_order = edge_index_g2,
edge_weights = edge_weights.float(),
edge_weights_higher_order = edge_weights_higher_order.float(),
bipartite_edge_index = bipatite_edge_index,
y = torch.tensor([ int(i) // 10 for i in paths.node_id])
)
DBGNN¶
In [27]:
Copied!
from sklearn.metrics import balanced_accuracy_score
def test(model, data):
model.eval()
_, pred = model(data).max(dim=1)
metrics_train = balanced_accuracy_score(
data.y[data.train_mask].cpu(),
pred[data.train_mask].cpu().numpy()
)
metrics_test = balanced_accuracy_score(
data.y[data.test_mask].cpu(),
pred[data.test_mask].cpu().numpy()
)
return metrics_train, metrics_test
from sklearn.metrics import balanced_accuracy_score
def test(model, data):
model.eval()
_, pred = model(data).max(dim=1)
metrics_train = balanced_accuracy_score(
data.y[data.train_mask].cpu(),
pred[data.train_mask].cpu().numpy()
)
metrics_test = balanced_accuracy_score(
data.y[data.test_mask].cpu(),
pred[data.test_mask].cpu().numpy()
)
return metrics_train, metrics_test
In [28]:
Copied!
data = RandomNodeSplit(num_val=0, num_test=0.3)(data)
model = DBGNN(
num_features =[num_nodes, num_ho_nodes],
num_classes = len(data.y.unique()),
hidden_dims = [16, 32, 8],
p_dropout = 0.4
).to(device)
optimizer = torch.optim.Adam(model.parameters(), lr=0.005)
loss_function = torch.nn.CrossEntropyLoss()
data = data.to(device)
data = RandomNodeSplit(num_val=0, num_test=0.3)(data)
model = DBGNN(
num_features =[num_nodes, num_ho_nodes],
num_classes = len(data.y.unique()),
hidden_dims = [16, 32, 8],
p_dropout = 0.4
).to(device)
optimizer = torch.optim.Adam(model.parameters(), lr=0.005)
loss_function = torch.nn.CrossEntropyLoss()
data = data.to(device)
In [29]:
Copied!
data
data
Out[29]:
Data(x=[30, 30], edge_index=[2, 557], y=[30], num_nodes=30, num_ho_nodes=557, x_h=[557, 557], edge_index_higher_order=[2, 6572], edge_weights=[557], edge_weights_higher_order=[6572], bipartite_edge_index=[2, 557], train_mask=[30], val_mask=[30], test_mask=[30])
In [30]:
Copied!
print(model)
print(model)
DBGNN(
(higher_order_layers): ModuleList(
(0): GCNConv(557, 16)
(1): GCNConv(16, 32)
)
(first_order_layers): ModuleList(
(0): GCNConv(30, 16)
(1): GCNConv(16, 32)
)
(bipartite_layer): BipartiteGraphOperator()
(lin): Linear(in_features=8, out_features=3, bias=True)
)
In [31]:
Copied!
losses = []
for epoch in range(1000):
output = model(data)
loss = loss_function(output[data.train_mask], data.y[data.train_mask])
loss.backward()
optimizer.step()
optimizer.zero_grad()
losses.append(loss)
if epoch % 10 == 0:
train_ba, test_ba = test(model, data)
print(f'Epoch: {epoch}, Loss: {loss}, Train balanced accuracy: {train_ba}, Test balanced accuracy: {test_ba}')
losses = []
for epoch in range(1000):
output = model(data)
loss = loss_function(output[data.train_mask], data.y[data.train_mask])
loss.backward()
optimizer.step()
optimizer.zero_grad()
losses.append(loss)
if epoch % 10 == 0:
train_ba, test_ba = test(model, data)
print(f'Epoch: {epoch}, Loss: {loss}, Train balanced accuracy: {train_ba}, Test balanced accuracy: {test_ba}')
Epoch: 0, Loss: 1.227025032043457, Train balanced accuracy: 0.3333333333333333, Test balanced accuracy: 0.3333333333333333 Epoch: 10, Loss: 0.6666216850280762, Train balanced accuracy: 0.6666666666666666, Test balanced accuracy: 0.6666666666666666 Epoch: 20, Loss: 0.09434882551431656, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 30, Loss: 0.0014071125769987702, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 40, Loss: 0.00030880115809850395, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 50, Loss: 0.0001672431972110644, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 60, Loss: 0.00011002655082847923, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 70, Loss: 8.51466174935922e-05, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 80, Loss: 7.0924885221757e-05, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 90, Loss: 6.107875378802419e-05, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 100, Loss: 5.376345507102087e-05, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 110, Loss: 4.805967182619497e-05, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 120, Loss: 4.343973705545068e-05, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 130, Loss: 3.959159948863089e-05, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 140, Loss: 3.632800871855579e-05, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 150, Loss: 3.3529791835462674e-05, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 160, Loss: 3.1117517210077494e-05, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 170, Loss: 2.900604704336729e-05, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 180, Loss: 2.7149984816787764e-05, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 190, Loss: 2.5509601982776076e-05, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 200, Loss: 2.4011105779209174e-05, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 210, Loss: 2.2694241124554537e-05, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 220, Loss: 2.1479540009750053e-05, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 230, Loss: 2.0384035451570526e-05, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 240, Loss: 1.9385019186302088e-05, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 250, Loss: 1.8454114979249425e-05, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 260, Loss: 1.7619706341065466e-05, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 270, Loss: 1.6842053810250945e-05, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 280, Loss: 1.6104137102956884e-05, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 290, Loss: 1.5440009519807063e-05, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 300, Loss: 1.47985856528976e-05, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 310, Loss: 1.4213922440831084e-05, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 320, Loss: 1.3663317076861858e-05, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 330, Loss: 1.3135416338627692e-05, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 340, Loss: 1.2641573448490817e-05, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 350, Loss: 1.2193138900329359e-05, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 360, Loss: 1.1761733730963897e-05, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 370, Loss: 1.1353033187333494e-05, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 380, Loss: 1.0955684956570622e-05, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 390, Loss: 1.0592395483399741e-05, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 400, Loss: 1.025181063596392e-05, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 410, Loss: 9.905548722599633e-06, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 420, Loss: 9.610374036128633e-06, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 430, Loss: 9.309522283729166e-06, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 440, Loss: 9.031377885548864e-06, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 450, Loss: 8.747555511945393e-06, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 460, Loss: 8.480761607643217e-06, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 470, Loss: 8.248027370427735e-06, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 480, Loss: 8.026645446079783e-06, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 490, Loss: 7.805261702742428e-06, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 500, Loss: 7.583881142636528e-06, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 510, Loss: 7.373850621661404e-06, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 520, Loss: 7.19220361133921e-06, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 530, Loss: 6.999202923907433e-06, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 540, Loss: 6.823232070019003e-06, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 550, Loss: 6.63590708427364e-06, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 560, Loss: 6.471289452747442e-06, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 570, Loss: 6.318023679341422e-06, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 580, Loss: 6.164757451188052e-06, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 590, Loss: 6.022844900144264e-06, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 600, Loss: 5.8752552831720095e-06, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 610, Loss: 5.756049631600035e-06, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 620, Loss: 5.619813236990012e-06, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 630, Loss: 5.506282832357101e-06, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 640, Loss: 5.375722594180843e-06, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 650, Loss: 5.2508389671857e-06, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 660, Loss: 5.148661784915021e-06, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 670, Loss: 5.035130925534759e-06, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 680, Loss: 4.927277132082963e-06, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 690, Loss: 4.8364522626798134e-06, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 700, Loss: 4.745627848024014e-06, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 710, Loss: 4.654803433368215e-06, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 720, Loss: 4.563979018712416e-06, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 730, Loss: 4.478830760490382e-06, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 740, Loss: 4.399358658702113e-06, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 750, Loss: 4.302858087612549e-06, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 760, Loss: 4.2233859858242795e-06, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 770, Loss: 4.14391388403601e-06, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 780, Loss: 4.08147252528579e-06, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 790, Loss: 4.007677034678636e-06, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 800, Loss: 3.933881998818833e-06, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 810, Loss: 3.871439730573911e-06, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 820, Loss: 3.826027295872336e-06, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 830, Loss: 3.7465554214577423e-06, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 840, Loss: 3.6727599308505887e-06, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 850, Loss: 3.621670884967898e-06, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 860, Loss: 3.5649056826514425e-06, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 870, Loss: 3.5138166367687518e-06, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 880, Loss: 3.462727590886061e-06, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 890, Loss: 3.4173153835581616e-06, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 900, Loss: 3.3491965041321237e-06, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 910, Loss: 3.303783614683198e-06, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 920, Loss: 3.264047563789063e-06, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 930, Loss: 3.2129585179063724e-06, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 940, Loss: 3.1561926334688906e-06, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 950, Loss: 3.1164572646957822e-06, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 960, Loss: 3.054014541703509e-06, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 970, Loss: 3.0199551019904902e-06, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 980, Loss: 2.9688660561077995e-06, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0 Epoch: 990, Loss: 2.9291297778399894e-06, Train balanced accuracy: 1.0, Test balanced accuracy: 1.0
Latent space representation of edges¶
In [32]:
Copied!
g2.node_index_to_id[0]
g2.node_index_to_id[0]
Out[32]:
(0, 1)
In [33]:
Copied!
model.eval()
latent = model.higher_order_layers[0].forward(data.x_h, data.edge_index_higher_order).detach()
node_embedding = TSNE(n_components=2, learning_rate='auto', init='random').fit_transform(latent.cpu())
colors = []
for v, w in g2.nodes:
if data.y[v] == 0 and data.y[w] == 0:
colors.append('red')
elif data.y[v] == 1 and data.y[w] == 1:
colors.append('green')
elif data.y[v] == 2 and data.y[w] == 2:
colors.append('blue')
else:
colors.append('grey')
plt.figure(figsize=(13,10))
plt.scatter(node_embedding[:,0], node_embedding[:,1], c=colors, alpha=0.5)
for e in g2.edges:
s = g2.node_id_to_index[e[0]]
t = g2.node_id_to_index[e[1]]
plt.plot([node_embedding[s,0], node_embedding[t,0]], [node_embedding[s,1], node_embedding[t,1]],
color='lightsteelblue',
linestyle='-',
alpha=0.2,
lw=0.2)
plt.axis('off')
plt.show()
model.eval()
latent = model.higher_order_layers[0].forward(data.x_h, data.edge_index_higher_order).detach()
node_embedding = TSNE(n_components=2, learning_rate='auto', init='random').fit_transform(latent.cpu())
colors = []
for v, w in g2.nodes:
if data.y[v] == 0 and data.y[w] == 0:
colors.append('red')
elif data.y[v] == 1 and data.y[w] == 1:
colors.append('green')
elif data.y[v] == 2 and data.y[w] == 2:
colors.append('blue')
else:
colors.append('grey')
plt.figure(figsize=(13,10))
plt.scatter(node_embedding[:,0], node_embedding[:,1], c=colors, alpha=0.5)
for e in g2.edges:
s = g2.node_id_to_index[e[0]]
t = g2.node_id_to_index[e[1]]
plt.plot([node_embedding[s,0], node_embedding[t,0]], [node_embedding[s,1], node_embedding[t,1]],
color='lightsteelblue',
linestyle='-',
alpha=0.2,
lw=0.2)
plt.axis('off')
plt.show()
In [34]:
Copied!
model.eval()
latent = model.higher_order_layers[1].forward(latent.cpu(), data.edge_index_higher_order).detach()
node_embedding = TSNE(n_components=2, learning_rate='auto', init='random').fit_transform(latent.cpu())
colors = []
for v, w in g2.nodes:
if data.y[v] == 0 and data.y[w] == 0:
colors.append('red')
elif data.y[v] == 1 and data.y[w] == 1:
colors.append('green')
elif data.y[v] == 2 and data.y[w] == 2:
colors.append('blue')
else:
colors.append('grey')
plt.figure(figsize=(13,10))
plt.scatter(node_embedding[:,0], node_embedding[:,1], c=colors, alpha=0.5)
for e in g2.edges:
s = g2.node_id_to_index[e[0]]
t = g2.node_id_to_index[e[1]]
plt.plot([node_embedding[s,0], node_embedding[t,0]], [node_embedding[s,1], node_embedding[t,1]],
color='lightsteelblue',
linestyle='-',
alpha=0.2,
lw=0.2)
plt.axis('off')
plt.show()
model.eval()
latent = model.higher_order_layers[1].forward(latent.cpu(), data.edge_index_higher_order).detach()
node_embedding = TSNE(n_components=2, learning_rate='auto', init='random').fit_transform(latent.cpu())
colors = []
for v, w in g2.nodes:
if data.y[v] == 0 and data.y[w] == 0:
colors.append('red')
elif data.y[v] == 1 and data.y[w] == 1:
colors.append('green')
elif data.y[v] == 2 and data.y[w] == 2:
colors.append('blue')
else:
colors.append('grey')
plt.figure(figsize=(13,10))
plt.scatter(node_embedding[:,0], node_embedding[:,1], c=colors, alpha=0.5)
for e in g2.edges:
s = g2.node_id_to_index[e[0]]
t = g2.node_id_to_index[e[1]]
plt.plot([node_embedding[s,0], node_embedding[t,0]], [node_embedding[s,1], node_embedding[t,1]],
color='lightsteelblue',
linestyle='-',
alpha=0.2,
lw=0.2)
plt.axis('off')
plt.show()
Latent space representation of nodes¶
In [35]:
Copied!
model.eval()
latent = model.forward(data).detach()
node_embedding = TSNE(n_components=2, learning_rate='auto', init='random', perplexity=10).fit_transform(latent.cpu())
colors = []
for v in g.nodes:
if data.y[v] == 0:
colors.append('red')
elif data.y[v] == 1:
colors.append('green')
elif data.y[v] == 2:
colors.append('blue')
else:
colors.append('grey')
plt.figure(figsize=(13,10))
plt.scatter(node_embedding[:,0], node_embedding[:,1], c=colors, alpha=0.5)
for e in g.edges:
s = e[0]
t = e[1]
plt.plot([node_embedding[s,0], node_embedding[t,0]], [node_embedding[s,1], node_embedding[t,1]],
color='lightsteelblue',
linestyle='-',
alpha=0.2,
lw=0.2)
plt.axis('off')
plt.show()
model.eval()
latent = model.forward(data).detach()
node_embedding = TSNE(n_components=2, learning_rate='auto', init='random', perplexity=10).fit_transform(latent.cpu())
colors = []
for v in g.nodes:
if data.y[v] == 0:
colors.append('red')
elif data.y[v] == 1:
colors.append('green')
elif data.y[v] == 2:
colors.append('blue')
else:
colors.append('grey')
plt.figure(figsize=(13,10))
plt.scatter(node_embedding[:,0], node_embedding[:,1], c=colors, alpha=0.5)
for e in g.edges:
s = e[0]
t = e[1]
plt.plot([node_embedding[s,0], node_embedding[t,0]], [node_embedding[s,1], node_embedding[t,1]],
color='lightsteelblue',
linestyle='-',
alpha=0.2,
lw=0.2)
plt.axis('off')
plt.show()
In [ ]:
Copied!
In [ ]:
Copied!